package org.myspringframework.beans.factory.xml;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.myspringframework.beans.BeansException;
import org.myspringframework.beans.factory.config.beandefinition.PropertyValue;
import org.myspringframework.beans.factory.config.beandefinition.PropertyValues;
import org.myspringframework.beans.factory.config.beandefinition.BeanDefinition;
import org.myspringframework.beans.factory.config.beandefinition.BeanReference;
import org.myspringframework.beans.factory.config.beandefinition.AbstractBeanDefinitionReader;
import org.myspringframework.beans.factory.config.beandefinition.BeanDefinitionRegistry;
import org.myspringframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.myspringframework.core.io.Resource;
import org.myspringframework.core.io.ResourceLoader;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
        super(registry);
    }

    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
        super(registry, resourceLoader);
    }

    @Override
    public void loadBeanDefinitions(Resource resource) throws BeansException {
        try {
            try (InputStream inputStream = resource.getInputStream()) {
                doLoadBeanDefinitions(inputStream);
            }
        } catch (IOException | ClassNotFoundException | DocumentException e ) {
            throw new BeansException("无法读取资源:" + resource, e);
        }
    }

    @Override
    public void loadBeanDefinitions(Resource... resources) throws BeansException {
        for (Resource resource : resources) {
            loadBeanDefinitions(resource);
        }
    }

    @Override
    public void loadBeanDefinitions(String location) throws BeansException {
        ResourceLoader resourceLoader = getResourceLoader();
        Resource resource = resourceLoader.getResource(location);
        loadBeanDefinitions(resource);
    }

    @Override
    public void loadBeanDefinitions(String... locations) throws BeansException {
        for (String location : locations) {
            loadBeanDefinitions(location);
        }
    }

    //读取配置文件加载beanDefinition
    protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException, DocumentException {
        SAXReader reader = new SAXReader();
        Document doc = reader.read(inputStream);
        //读取根结点<beans>
        Element rootElement = doc.getRootElement();
        //读取每个<bean>
        List<Element> beanList = rootElement.selectNodes("//bean");
        //读取context:component-scan 获取BasePackages

        Element componentScan = rootElement.element("component-scan");

        //遍历每个<bean>
        for (Element element : beanList) {
            //beanName
            String beanName = element.attributeValue("id");
            String classPath = element.attributeValue("class");
            String initMethod = element.attributeValue("init-method");
            String destroyMethod = element.attributeValue("destroy-method");
            String scope=element.attributeValue("scope");
            if (beanName==null||beanName==""){
                //将类名作为beanName
                String str = classPath.substring(classPath.lastIndexOf(".")+1);
                beanName=String.valueOf(str.charAt(0)).toLowerCase()+str.substring(1);
            }
            //这个bean的class类
            Class<?> classType = Class.forName(classPath);
            BeanDefinition beanDefinition=new BeanDefinition(classType);
            beanDefinition.setInitMethodName(initMethod);
            beanDefinition.setDestroyMethodName(destroyMethod);
            if (scope!=null&&scope!=""){
                beanDefinition.setScope(scope);
            }

            //处理属性值
            PropertyValues propertyValues=null;
            List<Element> propertyList = element.elements("property");
            if (propertyList!=null&&propertyList.size()>0){
                //有<property>标签，处理属性值
                propertyValues=new PropertyValues();
                for (Element property : propertyList) {
                    //属性名
                    String fieldName = property.attributeValue("name");
                    //属性值
                    String fieldValue = property.attributeValue("value");
                    //属性值(引用类型)
                    String fieldRef = property.attributeValue("ref");

                    PropertyValue propertyValue;
                    if (fieldValue!=null&&fieldValue!=""){
                        //为值
                        propertyValue=new PropertyValue(fieldName,fieldValue);
                    }else {
                        //为引用
                        propertyValue=new PropertyValue(fieldName,new BeanReference(fieldRef));
                    }
                    propertyValues.addPropertyValue(propertyValue);
                }
            }

            if (propertyValues!=null)
            beanDefinition.setPropertyValues(propertyValues);

            // 注册 BeanDefinition
            if (getRegistry().containsBeanDefinition(beanName)){
                throw new BeansException("不能有相同名称的bean:" + beanName + "已存在");
            }
            getRegistry().registerBeanDefinition(beanName, beanDefinition);
        }

        //扫描basePackages并注册BeanDefinition
        if (componentScan!=null){
            scanPackage(componentScan.attributeValue("base-package"));
        }

    }

    //扫描包下的@component注册为BeanDefinition
    private void scanPackage(String scanPath) {
        String[] basePackages = scanPath.split(",");
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(getRegistry());
        scanner.doScan(basePackages);
    }
}